home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / HEAP_UTL / HDEB20S / LIESMICH.TXT < prev    next >
Text File  |  1995-04-17  |  54KB  |  1,099 lines

  1.  
  2.  
  3.  
  4.  
  5.  
  6.  
  7.  
  8.  
  9.  
  10.  
  11.  
  12.  
  13.  
  14.  
  15.  
  16.  
  17.  
  18.  
  19.                                      Der
  20.  
  21.                               HEAP DEBUGGER V2.0
  22.  
  23.                                      für
  24.                              BORLAND PASCAL V7.0
  25.                            (DOS, DOS/DPMI, WINDOWS)
  26.  
  27.  
  28.                                 Copyright 1995
  29.                                       by
  30.  
  31.                                    AIT GmbH
  32.                          Alte Gasse 12 - 86152 Augsburg
  33.                                     Germany
  34.  
  35.                             Tel. +49 (821) 514868
  36.                             Fax: +49 (821) 514831
  37.  
  38.                   FIDO-Net: Karsten Strobel @ 2:2480/300.7
  39.                   Internet: kstrobel@gewi.muc.nacamar.de
  40.  
  41.  
  42.  
  43.  
  44.  
  45.  
  46.                                         INHALT
  47.  
  48.  
  49.       EINFÜHRUNG
  50.  
  51.       Der Sinn des Heap Debuggers .........................................  3
  52.       Was der Heap Debugger kann ..........................................  3
  53.       Was der Heap Debugger NICHT kann ....................................  3
  54.       Der Umgang mit dynamischem Speicher .................................  3
  55.       Versionen und Zielplattformen .......................................  4
  56.       Liste der Dateien ...................................................  5
  57.       Sharewarekonzept ....................................................  5
  58.       Lizenzbedingungen ...................................................  5
  59.       Nutzungsempfehlungen und Haftungsausschlüsse ........................  6
  60.  
  61.       ANWENDUNG DES HEAP DEBUGGERS
  62.  
  63.       Den Heap Debugger einbinden .........................................  6
  64.       Compiler- und Linkereinstellungen ...................................  7
  65.       Wenn die Initialisierung fehlschlägt ................................  7
  66.       Der Heap Debugger Report ............................................  8
  67.       Besondere Meldungen im Heap Debugger Report .........................  9
  68.       Interpretation des Reports .......................................... 10
  69.       Auffinden von Bugs .................................................. 11
  70.       Arbeiten mit einem externen Debugger ................................ 11
  71.       Compilerschalter in USEHDEB ......................................... 12
  72.  
  73.  
  74.       HEAP DEBUGGING IM DETAIL
  75.  
  76.       Overlays ............................................................ 13
  77.       DLLs ................................................................ 13
  78.       Programminstanzen (Windows) ......................................... 14
  79.       Interrupts .......................................................... 14
  80.       Stabilität und Performance .......................................... 14
  81.       Eingriffsmöglichkeiten für den Programmierer ........................ 15
  82.  
  83.  
  84.       BEKANNTE EINSCHRÄNKUNGEN UND PROBLEME
  85.  
  86.       Mark/Release ........................................................ 16
  87.       MemAllocSeg ......................................................... 17
  88.       BGI ................................................................. 18
  89.       TMemoryStream ....................................................... 18
  90.       Heapüberlauf ........................................................ 18
  91.       Programmabbruch ..................................................... 19
  92.       WINCRT .............................................................. 19
  93.  
  94.       Seite 3
  95.  
  96.  
  97.       EINFÜHRUNG _____________________________________________________________
  98.  
  99.       ___ Der Sinn des Heap Debuggers ________________________________________
  100.  
  101.       Der Heap Debugger überwacht (fast) alle vom Programm vorgenommenen Heap-
  102.       Operationen und führt unter anderem eine Liste über alle nicht freigege-
  103.       benen Heapspeicherbereiche. Der Programmierer, der den Heap Debugger
  104.       während der Entwicklungsphase in sein Programm einbindet, wird nach je-
  105.       dem Programmabschluß auf übriggebliebene Speicherblöcke hingewiesen.
  106.  
  107.       Der Heap Debugger macht das Auffinden der Fehlerquellen extrem einfach,
  108.       weil er (meistens) einen Hinweis auf die Sourcecodestelle (Dateiname und
  109.       Zeile) liefert, an der die inkorrekte Heap-Operation vorgenommen wurde
  110.       bzw. an der ein später nicht wieder freigegebener Speicherblock allo-
  111.       ziert wurde.
  112.  
  113.       Hierzu bedient sich der Heap Debugger der Debug-Informationen für den
  114.       externen Debugger, die (optional) an das vom Compiler erzeugte EXE-File
  115.       angehängt werden.
  116.  
  117.  
  118.       ___ Was der Heap Debugger kann _________________________________________
  119.  
  120.       Der Heap Debugger überwacht alle Allokationen von Heapspeicher, die mit
  121.       den Befehlen
  122.  
  123.          - GetMem
  124.          - New
  125.          - FreeMem
  126.          - Dispose
  127.  
  128.       vorgenommen werden. Auch Aufrufe dieser Routinen aus der Run-Time-
  129.       Library und aus Programmteilen heraus, die nicht im Sourcecode vorliegen
  130.       (z.B. fremde TPUs), werden berücksichtigt.
  131.  
  132.       Alle nicht korrekt deallokierten Heapspeicherblöcke und sonstige fehler-
  133.       hafte Heap-Operationen werden im Heap Debugger Report ausgegeben.
  134.  
  135.  
  136.       ___ Was der Heap Debugger NICHT kann ___________________________________
  137.  
  138.       Folgende Heap-Operationen können vom Heap Debugger NICHT mitverfolgt
  139.       werden:
  140.  
  141.          - Mark und Release (dürfen gar nicht verwendet werden !)
  142.  
  143.          - direkte Operationen mit dem globalen Heap (DPMI+Windows),
  144.            also alle "Global..."-Aufrufe
  145.  
  146.          - direkte Operationen mit dem lokalen Heap (Windows),
  147.            also alle "Local..."-Aufrufe
  148.  
  149.  
  150.       ___ Der Umgang mit dynamischem Speicher ________________________________
  151.  
  152.       In Programme, die intensiv mit Heapspeicher umgehen, schleichen sich
  153.       nicht selten heimtückische Programmierfehler ein: Wenn nämlich dynamisch
  154.       angeforderte Speicherbereiche nicht korrekt wieder freigegeben werden,
  155.       schrumpft der noch verfügbare Heapspeicher nach und nach so weit zu-
  156.  
  157.       Seite 4
  158.  
  159.  
  160.       sammen, daß irgendwann für eine neue Anforderung nicht mehr genügend
  161.       Platz zur Verfügung steht und das Programm abbricht oder -stürzt.
  162.  
  163.       Zum völligen Aufzehren des Heapspeichers kommt es natürlich nur, wenn
  164.       Allokationen ohne entsprechende Deallokationen nicht nur einmal, sondern
  165.       wiederholt durchgeführt werden. Wenn dieses z.B. mit der Anwahl einer
  166.       bestimmten Programmfunktion durch den Benutzer verbunden ist, dann kann
  167.       dies vielleicht einige hundert Male gut gehen, bis der übrige Heapspei-
  168.       cher aufgebraucht ist. So intensiv werden aber Programme nur selten vom
  169.       Programmierer getestet. Also kommen so bedingte Abstürze in der Regel
  170.       erst beim Benutzer vor, der dafür natürlich keine Erklärung hat.
  171.  
  172.       Es gibt auch Allokationen, die nur einmalig, also zum Beispiel in der
  173.       Initialisierungsphase vorgenommen werden, weil das Programm Speicher-
  174.       platz für quasi-statische Variablen benötigt. Solche Variablen (bzw.
  175.       Strukturen oder Objekte) könnte der Pogrammierer auch im Datensegment
  176.       (als globale Variablen) allokierten, aber da die Größe des Datensegmen-
  177.       tes auf insgesamt 64KB beschränkt ist, wird manchmal der Heap als Aus-
  178.       weg gewählt. Wenn solche (nur einmalig allokierten) quasi-statischen
  179.       Variablen nicht wieder freigegeben werden, so ist dies nur ein Schön-
  180.       heitsfehler, hat aber sonst keine Konsequenzen. Der Heap Debugger be-
  181.       mängelt aber natürlich auch solche Delikte.
  182.  
  183.       Besonders tückisch sind Deallokationsfehler, d.h. fehlerhafte Freigaben
  184.       von Heapspeicher. Ein Deallokationsfehler liegt vor, wenn bei der
  185.       Freigabe von Heapspeicher eine falsche Adresse oder eine falsche Länge
  186.       angegeben wird, also zu der unternommenen Deallokation zuvor keine pas-
  187.       sende Allokation erfolgt ist. Da sich die Runtime-Library weitgehend auf
  188.       die Angaben des Programmierers verläßt, können Deallokationsfehler ver-
  189.       heerende Folgen haben.
  190.  
  191.       Besonders die Objektorientierte Programmierung macht intensiv von Heap-
  192.       speicher Gebrauch. Zu jeder neuen Instanz eines Objektes wird ein Heap-
  193.       speicherblock für die Felder des Objektes angefordert, der beim Löschen
  194.       der Instanz wieder freigegeben werden muß. Hierzu bedient man sich der
  195.       Befehle New und Dispose in der speziell für OOP-Zwecke erweiterten
  196.       Syntax. Auch "vergessene" Objekte konsumieren Heapspeicher.
  197.  
  198.  
  199.       ___ Versionen und Zielplattformen ______________________________________
  200.  
  201.       Der Heap Debugger wurde entwickelt und getestet mit
  202.  
  203.                   Borland Pascal V7.0 und V7.01
  204.  
  205.                   mit den Zielsystemen
  206.                   - Real Mode (hierfür HDEB7?.TPU)
  207.                   - Protected Mode (hierfür HDEB7?.TPP)
  208.                   - Windows (hierfür HDEB7?.TPW)
  209.  
  210.                   unter
  211.                   - DOS 6.2x
  212.                   - Windows V3.1
  213.                   - Windows for Workgroups V3.11
  214.                   - Windows NT 3.5 Workstation
  215.                   - OS/2 V2.11
  216.  
  217.       Eine Version für Delphi V1.0 für Windows ist in Vorbereitung.
  218.  
  219.       Seite 5
  220.  
  221.  
  222.       ___ Liste der Dateien __________________________________________________
  223.  
  224.       USEHDEB.PAS .... Unit zum Einbinden in Pascalprogramme, für
  225.                        DOS, DOS/DPMI und WINDOWS
  226.       HDEB7S.TPU ..... Der Kern des Heap Debuggers, nur bei
  227.                        Sharewareversionen, für DOS/Real Mode
  228.       HDEB7S.TPP ..... Der Kern des Heap Debuggers, nur bei
  229.                        Sharewareversionen, für DOS/Protected Mode
  230.       HDEB7S.TPW ..... Der Kern des Heap Debuggers, nur bei
  231.                        Sharewareversionen, für Windows
  232.       HDEB7F.TPU ..... Der Kern des Heap Debuggers, nur bei
  233.                        Vollversionen für DOS/Real Mode
  234.       HDEB7F.TPP ..... Der Kern des Heap Debuggers, nur bei
  235.                        Vollversionen für DOS/Protected Mode
  236.       HDEB7F.TPW ..... Der Kern des Heap Debuggers, nur bei
  237.                        Vollversionen für Windows
  238.       VIEWME.EXE ..... Der Heap Debugger in Bildern (VGA)
  239.       README.TXT ..... Dieser Text (englisch)
  240.       LIESMICH.TXT ... Dieser Text (deutsch)
  241.       DIZFILES.ZIP ... Für Sysops, nur in Sharewareversionen
  242.       SHARWARE.ZIP ... Diese Datei ist nur in Vollversionen
  243.                        enthalten und enthält die Sharewareversion
  244.       BESTELL.TXT .... Bestellformular (deutsch)
  245.       ORDER.TXT ...... Bestellformular (englisch)
  246.  
  247.  
  248.       ___ Sharewarekonzept ___________________________________________________
  249.  
  250.       Der Heap Debugger ist Shareware, also KEINE Public Domain oder Freeware!
  251.  
  252.       Die über Sharewarevertriebswege verbeitete Version des Heap Debuggers in
  253.       den Dateien HDEB7S.* ("S"=Shareware) und die Begleitdateien und die
  254.       Datei USEHDEB.PAS dürfen zu Testzwecken genutzt und an andere weiterge-
  255.       geben werden.
  256.  
  257.       Die Sharewareversion ist gegenüber der Vollversion im Leistungsumfang
  258.       beschränkt: Die Sharewareversion des Heap Debuggers verfolgt nur die
  259.       ersten 50 Allokationen von Heapspeicherblöcken. Alle folgenden Allo-
  260.       kationen werden ignoriert. Bei Überschreitung des Sharewarelimits wird
  261.       bei Ausgabe des Reports (bei Programmende) eine entsprechende Meldung
  262.       ausgegeben.
  263.  
  264.       Registrierte Vollversionen des Heap Debuggers beinhalten die Dateien
  265.       HDEB7F.* ("F"=Full). Diese Dateien dürfen NICHT an Dritte weitergegeben
  266.       oder ihnen zugänglich gemacht werden.
  267.  
  268.  
  269.       ___ Lizenzbedingungen __________________________________________________
  270.  
  271.       Wer den Heap Debugger in der unbeschränkten Vollversion nutzen möchte,
  272.       muß eine Registrierung bei den Autoren vornehmen und erhält im Zuge der
  273.       Lieferung der Vollversion eine Lizenz zur Nutzung der Vollversion auf
  274.       einem einzelnen Arbeitsplatz.
  275.  
  276.       Bei Nutzung des Heap Debuggers auf mehreren Arbeitsplätzen müssen auch
  277.       mehrere Registrierungen bestellt werden. Hierfür bieten wir Staffel-
  278.       preise an.
  279.  
  280.       Seite 6
  281.  
  282.  
  283.       Ein Registrierungsformular ist in der Datei BESTELL.TXT vorbereitet.
  284.  
  285.       Es ist ausdrücklich untersagt, die Vollversion des Heap Debuggers
  286.       weiterzugeben. Dies betrifft insbesondere die Dateien HDEB7F.*
  287.  
  288.  
  289.       ___ Nutzungsempfehlungen und Haftungsausschlüsse _______________________
  290.  
  291.       Obwohl wir den Heap Debugger vor der Veröffentlichung ausführlich getes-
  292.       tet haben, können wir keine Garantie für einwandfreie Funktion oder Feh-
  293.       lerfreiheit dieser Software übernehmen.
  294.  
  295.       Wir empfehlen die Nutzung des Heap Debuggers während der Entwicklungs-
  296.       phase. Nach Fertigstellung eines Softwareprodukts sollte unserer Meinung
  297.       nach der Heap Debugger nicht mehr eingebunden werden.
  298.  
  299.       Der Heap Debugger soll Ihnen bei der Softwareentwicklung helfen, Fehler
  300.       bei der Speicherverwaltung zu vermeiden oder zu beseitigen. Wir weisen
  301.       aber auch auf die zusätzlichen Gefahren für die Stabilität einer Soft-
  302.       ware, die den Heap Debugger einbindet, hin. Näheres hierzu siehe Ab-
  303.       schnitt "Stabilität und Performance".
  304.  
  305.       Bei Lieferungen dieser Software erstreckt sich unsere Garantie aus-
  306.       schließlich auf die Lesbarkeit des gelieferten Datenträgers. Wir über-
  307.       nehmen keinerlei Haftung für Schäden, die durch Benutzung des Heap
  308.       Debuggers eventuell entstehen werden.
  309.  
  310.  
  311.       ANWENDUNG DES HEAP DEBUGGERS ___________________________________________
  312.  
  313.       ___ Den Heap Debugger einbinden ________________________________________
  314.  
  315.       Um den Heap Debugger in ein eigenes Programm einzubinden, müssen Sie nur
  316.       die Unit UseHDeb in die Uses-Klausel Ihres Hauptprogramms aufnehmen.
  317.       Beispiel:
  318.  
  319.             PROGRAM MyProg;
  320.  
  321.                UseHDeb,
  322.                 \  /
  323.                  \/
  324.             USES   Drivers, Objects, Views, Menus, ...
  325.  
  326.       Es ist sinnvoll, die Unit UseHDeb als erste Unit in der Uses-Klausel
  327.       aufzuführen. Die Initialisierung des Heap Debuggers erfolgt über den
  328.       Initialisierungsteil dieser Unit. Erst nach der Initialisierung kann der
  329.       Heap Debugger Heap-Operationen "beobachten". Deshalb sollte die Initia-
  330.       lisierung von UseHDeb möglichst vor der Initialisierung anderer Units,
  331.       die eventuell schon Heap-Operationen machen, vorgenommen werden.
  332.  
  333.       Keine der Units, von denen die Units UseHDeb und HDeb7? ihrerseits di-
  334.       rekt oder indirekt Gebrauch machen, nimmt in der Initialisierungsphase
  335.       Heap-Allokationen vor. Der Heap Debugger erhält also von allen Heap-
  336.       Operationen Kenntnis, sofern keine der vom Heap Debugger genutzten Units
  337.       modifiziert worden sind.
  338.  
  339.       Seite 7
  340.  
  341.  
  342.       ___ Compiler- und Linkereinstellungen __________________________________
  343.  
  344.       "D+":
  345.  
  346.       Der Heap Debugger wird nur initialisiert, wenn die Unit UseHDeb mit der
  347.       Compileroption "D+" (Debug-Informationen ein) übersetzt wird. Das liegt
  348.       daran, daß fast die gesamte Unit UseHDeb mit Hilfe der Klausel
  349.       {$IFOPT D+}...{$ENDIF} von der Compilierung ausgeschlossen ist, wenn die
  350.       Option D+ nicht eingeschaltet ist. Dieser Schalter kann also zum Ein-
  351.       und Ausschalten des Heap Debuggers verwendet werden. Theoretisch könnte
  352.       der Heap Debugger allerdings auch ohne eingeschaltetes D+ laufen.
  353.  
  354.       Für alle anderen Units, die in Ihr Programm eingebunden werden, sowie
  355.       für das Hauptprogramm gilt: Nur wenn mit der Option D+ übersetzt wird,
  356.       kann der Heap Debugger in seinem Report Referenzen auf diese Quellda-
  357.       teien und Zeilennummern angeben.
  358.  
  359.       "Link-Puffer: Festplatte" und "Externer Debugger":
  360.  
  361.       Damit der Heap Debugger im Report Referenzen auf Quelldateien und Zei-
  362.       lennummern liefern kann, müssen die dazu notwendigen Debug-Informa-
  363.       tionen in das vom Compiler erzeugte EXE-File (bzw. DLL) geschrieben wer-
  364.       den. Neben der Compileroption D+ werden dazu außerdem die Einstellungen
  365.       "Link-Puffer: Festplatte" und "Externer Debugger" benötigt. Unter Win-
  366.       dows heißt die letzte Option "Debug-Info in EXE".
  367.  
  368.       "Unit-Verzeichnis: \BP\RTL\WIN" (DOS/DPMI und Windows):
  369.  
  370.       Die Unit UseHDeb benötigt im Protected Mode (DOS+Windows) die Unit
  371.       WINPROCS. Diese befindet sich gewöhnlich im Verzeichnis "\BP\RTL\WIN".
  372.       Da unter DOS dieses Verzeichnis normalerweise nicht als Unit-Verzeichnis
  373.       (siehe Option-->Verzeichnisse) eingestellt ist, müssen Sie dieses Ver-
  374.       zeichnis selbst in der Liste der Unit-Verzeichnisse ergänzen.
  375.  
  376.  
  377.       ___ Wenn die Initialisierung fehlschlägt _______________________________
  378.  
  379.       Die Initialisierung des Heap Debuggers wird von dem Initialisierungteil
  380.       der Unit UseHDeb vorgenommen. Bei Fehlschlagen der Initialisierung gibt
  381.       UseHDeb die Meldung "Heap Debugger konnte nicht initialisiert werden !"
  382.       aus und stoppt das Programm mit dem Kommando HALT.
  383.  
  384.       Das Fehlschlagen der Initialisierung kann folgende Ursachen haben:
  385.  
  386.         - Sie verwenden eine modifizierte Run-Time-Library, die in
  387.           einem für den Heap Debugger wichtigen Punkt nicht mit dem
  388.           Original von Borland übereinstimmt.
  389.         - Sie verwenden ein von uns nicht getestetes Betriebssystem
  390.           oder spezielle, von uns nicht getestete Tools (z.B. zur
  391.           Speicherverwaltung).
  392.         - Sie verwenden eine von uns nicht getestete Compilerversion.
  393.         - Es wurden keine freien Interruptvektoren gefunden. Der
  394.           Heap Debugger benötigt drei freie Interrupts. In diesem
  395.           Falle ist wahrscheinlich unsere Testmethode zum Finden
  396.           freier Interrupts verantwortlich. Es kommt selten vor,
  397.           daß tatsächlich alle Interrupts belegt sind.
  398.         - Der Heap Debugger ist schon initilisiert. Dies sollte bei
  399.           Verwendung der Unit UseHDeb nicht vorkommen.
  400.  
  401.       Seite 8
  402.  
  403.  
  404.  
  405.       Wenn bei Ihrem System die Initialisierung des Heap Debuggers fehlschla-
  406.       gen sollte, dann versuchen Sie bitte zunächst, Ihr Programm in einer von
  407.       uns getesteten Konfiguration (z.B. MSDOS 6.2, ggf. Windows 3.1) ohne
  408.       vorheriges Laden irgendwelcher spezieller Speichermanager oder Multi-
  409.       tasker zu laden. Beobachten Sie, ob der Heap Debugger in dieser Konfi-
  410.       guration initialisiert werden kann.
  411.  
  412.       Bitte informieren Sie uns über Konfigurationen, in denen der Heap
  413.       Debugger nicht betrieben werden kann (möglichst per email).
  414.  
  415.       ___ Der Heap Debugger Report ___________________________________________
  416.  
  417.       Der Heap Debugger gibt beim Beenden des untersuchten Programms einen Re-
  418.       port aus. Dies geschieht in der Exit-Prozedur der Unit UseHDeb.
  419.  
  420.       Der Heap Debugger Report hat in der Regel folgenden Aufbau (Beispiel):
  421.  
  422.         HEAP DEBUGGER DIAGNOSE:
  423.         2 Pointer wurden registiert (*1)
  424.         1 Debug-Eintraege vorhanden (*2)
  425.         auflisten (J/N) ? j
  426.  
  427.         (*3)  (*4)      (*5)  (*6)           (*7)       |------(*8)------|
  428.         Nr    Pointer   Size  Flags          Aufrufer         Datei  Zeile
  429.          2  1A41:0000    256          0000[122D]:0044   HEAPBUG.PAS     16
  430.  
  431.  
  432.       (*1): Hier wird angegeben, wieviele Heap-Allokationen der Heap Debugger
  433.             insgesamt mitverfolgt hat. Diese Zahl enthält also noch keine
  434.             Aussage über eventuelle Fehler.
  435.       (*2): Hier wird angegeben, wieviele Diagnosezeilen der Heap Debugger
  436.             auszugeben hat. Im Idealfall sollte hier immer "0" stehen. Nicht
  437.             alle, aber die meisten Diagnosezeilen deuten auf einen Program-
  438.             mierfehler hin.
  439.       (*3): Hier wird eine laufende Nummer aller vom Programm vorgenommener
  440.             Allokationen ausgegeben. Bei Deallokationen (Flag "F") steht hier
  441.             nichts.
  442.       (*4): Hier wird die Adresse des allokierten bzw. deallokierten
  443.             Heapspeicherblocks ausgegeben. Diese Adresse kann von Programmlauf
  444.             zu Programmlauf variieren.
  445.       (*5): Hier wird die Größe des allokierten bzw. deallokieren Blocks
  446.             ausgegeben.
  447.       (*6): Die hier ausgegebenen Flags haben folgende Bedeutung
  448.             (Kombinationen sind möglich):
  449.  
  450.             keins: Es handelt sich um eine Allokation, zu der keine passende
  451.                    Deallokation erfolgt ist.
  452.             "O"  : Es handelt sich um die Daten einer Objektinstanz. Das ist
  453.                    der Datenbereich, der vom Constructor eines Objektes
  454.                    für die Felder des Objektes (und anderes) bei jeder neuen
  455.                    Instanz angelegt wird. Als Aufrufer wird die Zeile mit
  456.                    dem Word "BEGIN" des Construktors angegeben, bzw. die Zeile
  457.                    mit dem Word "END" des Destructors bei Deallokationen.
  458.             "F"  : Bei dieser Diagnosezeile geht es um eine Deallokation
  459.                    (F=free). Was bei dieser Deallokation schiefgegangen ist,
  460.                    wird mit einem der folgenden Flags angegeben.
  461.  
  462.       Seite 9
  463.  
  464.  
  465.             "S"  : Ein Heapspeicherblock wurde nicht mit der gleichen Block-
  466.                    länge (S=size) deallokiert, mit der er allokiert wurde. In
  467.                    diesem Falle wird dieses Flag sowohl in der Diagnosezeile
  468.                    der Allokation als auch in der der Deallokation ausgegeben.
  469.             "M"  : Zu einer Deallokation wurde keine passende Allokation
  470.                    gefunden (M=mismatch). Das heißt, daß versucht wurde, einen
  471.                    Heapspeicherblock zu deallokieren, dessen Adresse nicht bei
  472.                    einer vorangegangenen Allokation registriert worden ist.
  473.                    Dieses Flag tritt nur zusammen mit dem Flag "F" auf.
  474.  
  475.       (*7): Hier wird die Adresse der aufrufenden Programmstelle ausgegeben.
  476.             An dieser Programmstelle wurde die in der Diagnosezeile angegebene
  477.             Heap-Operation aufgerufen. Die Segmentadresse dieser Stelle ist
  478.             sowohl als virtuelle Segmentadresse (in eckigen Klammern "[]")
  479.             als auch aktuelle Segmentadresse angegeben. Die virtuelle Segment-
  480.             adresse wird vom Linker vergeben und ist die Adresse relativ zur
  481.             Adresse 0000. Die aktuelle Adresse wird beim Laden des Programms
  482.             vergeben und ist abhängig von der Stelle, an die das Programm in
  483.             den Speicher geladen wird. Die virtuelle Adresse findet sich im
  484.             MAP-File des Programms wieder. Die aktuelle Adresse kann von Pro-
  485.             grammlauf zu Programmlauf variieren.
  486.       (*8): Hier wird die Sourcecodestelle (Dateiname und Zeilennummer) ange-
  487.             geben, die sich die Aufrufer-Adresse bezieht. Voraussetzung dafür
  488.             ist, daß überhaupt Debug-Informationen im EXE-File existieren.
  489.             Sind keine Debug-Informationen vorhanden, dann wird hier
  490.             "keine Info." angezeigt. Wenn zwar Debug-Informationen vorhanden
  491.             sind, aber die Sourcecodestelle zu der Aufrufer-Adresse trotzdem
  492.             nicht gefunden werden konnte, dann wird hier "?" angezeigt.
  493.  
  494.  
  495.       ___ Besondere Meldungen im Heap Debugger Report ________________________
  496.  
  497.       Folgende Meldungen können im Heap Debugger Report in Ausnahmefällen auf-
  498.       treten:
  499.  
  500.       "Programm durch HALT(nnn) gestoppt"
  501.  
  502.       Diese Meldung erscheint, wenn das Programm gezielt mit dem Befehl
  503.       HALT(nnn) gestoppt wurde. Der Exitcode wird mit nnn angegeben.
  504.  
  505.       "Laufzeitfehler nnn bei ssss:oooo, Datei: ________ Zeile: _____"
  506.  
  507.       Wenn das Programm durch einen Laufzeitfehler abgebrochen wird, erscheint
  508.       diese Meldung. Als zusätzliche, nützliche Information wird die
  509.       Programmstelle des Laufzeitfehlers (Quelldateiname und Zeilennummer)
  510.       ausgegeben, sofern diese Information verfügbar ist.
  511.  
  512.       "interner Fehler 203 im Heap Debugger aufgetreten"
  513.  
  514.       Diese Meldung bedeutet, daß dem Heap Debugger zur Laufzeit nicht genü-
  515.       gend Heapspeicher zur Verfügung stand, um alle Heap-Operationen auf-
  516.       zeichnen zu können.
  517.  
  518.       "Shareware-Limit ueberschritten!
  519.        Es wurden nur 50 pointer verarbeitet!"
  520.  
  521.       Diese Meldung wird nur von der Sharewareversion ausgegeben und besagt,
  522.       daß das Sharewarelimit von 50 überwachten Allokationen zur Laufzeit
  523.       überschritten worden ist.
  524.  
  525.       Seite 10
  526.  
  527.  
  528.       ___ Interpretation des Reports _________________________________________
  529.  
  530.       Natürlich sollte man immer anstreben, am Ende eines Programmlaufs vom
  531.       Heap Debugger die Meldung "0 Debug-Eintraege vorhanden" gemacht zu
  532.       bekommen. Wenn der Heap Debugger während der gesamten Entwicklungszeit
  533.       einer Applikation kontinuierlich eingesetzt wird, dann läßt sich eine
  534.       nach einem Testlauf plötzlich auftauchende andere Meldung meist sehr
  535.       leicht mit der zuletzt vorgenommenen Programmänderung in Zusammenhang
  536.       bringen.
  537.  
  538.       Wenn die Sache einmal nicht so einfach ist, muß man die Diagnose des
  539.       Heap Debuggers zunächst einmal interpretieren, um dem Problem auf die
  540.       Schliche zu kommen.
  541.  
  542.       Hierzu sollte man sich die folgenden Fragen stellen:
  543.  
  544.       - Ist die Anzahl der Diagnoseeinträge immer gleich oder variiert diese
  545.         Anzahl ?
  546.  
  547.         Soweit die Anzahl nicht variiert, handelt es sich offenbar um
  548.         einmalig vorkommende Fehler im Programm. Es gibt Fälle, bei denen
  549.         die Bezeichnung Fehler sogar etwas zu scharf gewählt ist. Manche
  550.         Programme legen nämlich quasi-statische Variablen auf dem Heap an,
  551.         und geben diese dann am Ende nicht wieder frei. So ein Verhalten
  552.         ist zwar nicht sonderlich schön und sollte deshalb vermieden werden;
  553.         es hat andererseits aber auch keine schlimmen Konsequenzen.
  554.  
  555.       - Läßt sich das Anwachsen der Anzahl der Diagnosezeilen mit einer
  556.         bestimmten Funktion meines Programms in Zusammenhang bringen ?
  557.  
  558.         Wenn die Anzahl wächst, dann sollte man versuchen, den sich
  559.         offenbar wiederholenden Fehler auszumachen. Meistens ist das sehr
  560.         einfach, wenn nämlich der Heap Debugger für mehrere Einträge die
  561.         selbe Aufruferadresse ausgibt. Es handelt sich dann wohl um einen
  562.         Fehler, der immer dann zum Tragen kommt, wenn eine bestimmte
  563.         Programmfunktion ausgelöst wird. Solche Fehler sollte man auf jeden
  564.         Fall beseitigen, da sie den gefürchteten "Gedächtnisschwund" auslösen.
  565.  
  566.       - Wurde in einzelnen Diagnosezeilen irgendein Flag eingetragen ?
  567.  
  568.         Soweit nicht, handelt es sich bei den Diagnosen des Heap
  569.         Debuggers um Hinweise auf "klassische" Fehler, nämlich auf das
  570.         unterlassene Freigeben "normaler" Heapspeicherblöcke, die
  571.         mittels GetMem oder New angefordert wurden. Die Sourcecodereferenz
  572.         verweist auf die Stelle, an der diese Anforderung geschehen ist.
  573.  
  574.       - Wurde in einzelnen Diagnosezeilen das Flag "O" eingetragen ?
  575.  
  576.         Soweit ja, weist der Heap Debugger auf Verfehlungen im Zusammenhang
  577.         mit Objekten hin. Wird z.B. nur ein "O" eingetragen, dann handelt
  578.         es sich um nicht freigegebene Instanzdaten eines Objektes, welche
  579.         (im allgemeinen) mittels New in der OOP-Variante, nämlich
  580.         New(ptr, constructor), angelegt worden sind. Die Sourcecodereferenz
  581.         deutet aber dann NICHT auf diese New-Anweisung, sondern auf die
  582.         Zeile BEGIN im betreffenden Constructor. Wenn man diesen ausgemacht
  583.         hat, muß man überlegen, wo Instanzen dieses Objekttyps angelegt
  584.         werden und dort auf korrekte Freigaben prüfen.
  585.  
  586.       Seite 11
  587.  
  588.  
  589.       - Wurde in einzelnen Diagnosezeilen das Flag "F" eingetragen ?
  590.  
  591.         Dieses Flag kommt nie allein. Es bedeutet (meistens), daß ein Deallo-
  592.         kationsfehler passiert ist. Außer dem "F" ist immer entweder ein
  593.         "S" oder ein "M" gesetzt, was bedeutet, daß entweder eine Deallokation
  594.         mit einer falschen Blocklänge aufgerufen worden ist, bzw. daß der
  595.         deallokierte Speicherblock an einer Adresse liegt, an der vorher
  596.         keine Allokation vorgenommen worden ist.
  597.  
  598.         Solche Diagnosen sind entweder sehr schlimm oder sehr harmlos.
  599.         Der harmlose Fall ist im Abschnitt "MemAllocSeg" beschrieben. Wenn
  600.         diese Beschreibung nicht zutrifft, dann liegt wahrscheinlich ein
  601.         echter Fehler vor, der unbedingt gefunden werden muß, weil er das
  602.         gesamte Programm (auch den Heap Debugger) zum Absturz bringen kann.
  603.         Letzteres kann passieren, wenn die Konsistenz der Heapverwaltung
  604.         nicht mehr gegeben ist. In so einem Fall können übrigens auch Daten
  605.         auf dem Heap verstümmelt werden.
  606.  
  607.  
  608.       ___ Auffinden von Bugs _________________________________________________
  609.  
  610.       Wenn der Heap Debugger zu seinen Diagnosen Sourcecodereferenzen ausgeben
  611.       konnte, dann ist das Auffinden von Bugs verhältnismäßig einfach.
  612.  
  613.       Wenn die Sourcecodereferenz allerdings mit "?" angegeben wird, dann be-
  614.       findet sich die unter "Aufrufer" aufgeführte Adresse in einem Modul, das
  615.       nicht mit der Option "D+", also ohne Debuginformationen übersetzt worden
  616.       ist. Oft ist der Aufrufer dann in der Run-Time-Library zu finden.
  617.  
  618.       Man sollte sich aber nicht zu dem Schluß verleiten lassen, daß man für
  619.       den entsprechenden Fehler dann gar nicht verantwortlich ist und daß die
  620.       Run-Time-Library einen Bug hat. Wenn von Ihnen z.B. eine Allokation
  621.       mittels "NewStr" (Funktion der Run-Time-Library) vorgenommen wurde,
  622.       und der so angeforderte Heapspeicherblock wurde anschließend nicht
  623.       korrekt mit DisposeStr deallokiert, dann liegt der Fehler in Ihrem
  624.       Programmteil; als Aufrufer wird aber eine Zeile in der Funktion NewStr
  625.       genannt.
  626.  
  627.       Viele Probleme dieser Art kann man lösen, indem man die ganze
  628.       Run-Time-Library mit Debug-Option neu übersetzt. Das ist nur bei
  629.       BP7.0, nicht bei TP7.0 möglich. Informationen hierzu bietet Borland
  630.       in der Datei \BP\RTL\README.
  631.  
  632.  
  633.       ___ Arbeiten mit einem externen Debugger _______________________________
  634.  
  635.       In hartnäckigen Fällen kann man versuchen, einen Fehler mit Hilfe des
  636.       externen Debuggers einzugrenzen. Das ist besonders dann sinnvoll, wenn
  637.       man dem Heap Debugger trotz aller Bemühungen keine Sourcecodereferenz
  638.       entlocken kann.
  639.  
  640.       Im externen Debugger sollte man versuchen, auf die fragliche Programm-
  641.       stelle (die Aufruferadresse) einen Breakpoint zu setzen.
  642.  
  643.       Beachten Sie hierzu den Unterschied zwischen der virtuellen und der
  644.       aktuellen Segmentadresse, die der Heap Debugger ausgibt.
  645.  
  646.       Seite 12
  647.  
  648.  
  649.       Achtung: Die aktuelle Segmentadresse eines Aufrufers kann sich von
  650.       Programmlauf zu Programmlauf verschieben. Nach dem Laden des Debuggers
  651.       wird sie sich sogar sehr wahrscheindlich verschieben. Lassen Sie daher
  652.       Ihr Programm mit geladenem Debugger einmal oder mehrmals laufen, ohne
  653.       einen Breakpoint zu setzen. Verwenden sie die zuletzt ausgegebene
  654.       aktuelle Segmentadresse, um den Breakpoint zu setzen. Sie setzen einen
  655.       Breakpoint auf eine von Hand eingegebene Adresse mit der Funktion
  656.       "Breakpoints->At...". Geben Sie einfach die Adresse ein und beginnen Sie
  657.       die Segmentadresse UND die Offsetadresse jeweils mit "$" für hexadezi-
  658.       male Notation.
  659.  
  660.       Wenn Sie Ihr Programm dann starten und einen Breakpoint erreichen,
  661.       versuchen Sie das Programm ab dieser Stelle in Einzelschritten fortzu-
  662.       setzen, bis Sie zu einer Stelle des Programms kommen, die Ihnen bekannt
  663.       ist.
  664.  
  665.  
  666.       ___ Compilerschalter in USEHDEB ________________________________________
  667.  
  668.       In die Unit UseHDeb wurden bereits einige Compilerschalter eingeführt,
  669.       die die Anpassung an besondere Anforderungen erleichtern sollen. Wir
  670.       hoffen, daß damit die allermeisten Anpassungsprobleme zu lösen sind, so
  671.       daß dem Anwender eine weitergehende Veränderung des Sourcecodes erspart
  672.       bleibt.
  673.  
  674.       Der Schalter "USE_SHAREWARE":
  675.  
  676.       Wenn dieser Schalter aktiv ist, dann wird der Heap Debugger in einer der
  677.       Units "HDEB7S.TP?" benutzt. Wenn er ausgeschaltet ist, dann wird eine
  678.       der Units "HDEB7F.TP?" eingebunden. Letztere stellt die Vollversion des
  679.       Heap Debuggers dar und kann natürlich nur verwendet werden, wenn die
  680.       Software registriert worden ist. Dieser Compiler ist bei Lieferung der
  681.       Shareware- bzw. der Vollversion schon richtig eingestellt und muß also
  682.       in der Regel nicht verändert werden.
  683.  
  684.       Der Schalter "GERMAN_LANG":
  685.  
  686.       Wenn dieser Schalter aktiv ist, dann wird der Heap Debugger Report in
  687.       deutscher Sprache ausgegeben, sonst in Englisch.
  688.  
  689.       Der Schalter "GETDEBUGINFO":
  690.  
  691.       Wenn dieser Schalter aktiv ist, dann wird bei der Reportausgabe ver-
  692.       sucht, auf die Debug-Informationen im EXE-File zuzugreifen, um Dateina-
  693.       men und Zeilennummer zu jeder Diagnosezeile zu ermitteln. Dieser Schal-
  694.       ter sollte normalerweise aktiv bleiben.
  695.  
  696.       Der Schalter "REPORT_TO_FILE":
  697.  
  698.       Wenn dieser Schalter aktiv ist, dann wird die Reportausgabe der Unit
  699.       UseHDeb in eine Datei umgeleitet. Der Name dieser Datei wird mit der
  700.       Konstanten DumpFileName festgelegt und ist auf "HEAPDEB.DMP" voreinge-
  701.       stellt, kann aber verändert werden. Die Datei wird mit jeder Reportaus-
  702.       gabe erweitert. Bitte beachten Sie: Wenn der Heap Debugger aus irgendei-
  703.       nem Grund nicht initialisiert wurde und der Schalter "REPORT_TO_FILE"
  704.       aktiviert ist, dann wird das Programm ohne Ausgabe einer Meldung (auch
  705.       nicht in die Datei) mit dem Kommando "HALT" gestoppt.
  706.  
  707.       Seite 13
  708.  
  709.  
  710.       Der Schalter "SWITCH_TO_LASTMODE":
  711.  
  712.       Wenn dieser Schalter aktiv ist, dann wird vor der Reportausgabe der Unit
  713.       UseHDeb mit dem Kommando "Textmode(LastMode)" in den Videomodus zurück-
  714.       geschaltet, der beim Start des Programms aktiv war. Dies kann nützlich
  715.       sein, wenn das Hauptprogramm z.B. in einen vom BIOS nicht unterstützten
  716.       Grafikmodus umschaltet oder Textfarben so manipuliert, daß die Report-
  717.       ausgabe nicht lesbar ist. Dieser Schalter hat unter Windows keine Aus-
  718.       wirkung.
  719.  
  720.       Beispiel für das Ein- und Ausschalten eines Schalters:
  721.            aktiv:   "{$DEFINE GERMAN_LANG}"
  722.            inaktiv: "{not $DEFINE GERMAN_LANG}"
  723.  
  724.  
  725.       HEAP DEBUGGING IM DETAIL _______________________________________________
  726.  
  727.       ___ Overlays ___________________________________________________________
  728.  
  729.       Sie können den Heap Debugger auch innerhalb von Programmen nutzen, die
  730.       von Overlayprogrammierung Gebrauch machen. Die Units USEHDEB und HDEB7?
  731.       dürfen allerdings nicht als Overlays geladen werden.
  732.  
  733.  
  734.       ___ DLLs _______________________________________________________________
  735.  
  736.       Eine DLL kann man mit dem Heap Debugger behandeln wie ein normales, ei-
  737.       genständiges Programm. Wenn ein Programm, das den Heap Debugger verwen-
  738.       det, zur Laufzeit eine DLL einbindet, dann ist der Heap Debugger für
  739.       diese DLL nicht wirksam. Umgekehrt kann eine DLL den Heap Debugger ver-
  740.       wenden, ohne daß dadurch die Heap-Operationen im Hauptprogramm überwacht
  741.       werden. Wird sowohl in eine DLL alsauch in das Hauptprogramm der Heap
  742.       Debugger eingebunden, so werden zum Programmende zwei Reporte ausgege-
  743.       ben.
  744.  
  745.       Das Einbinden des Heap Debuggers in eine DLL erfolgt demgemäß auch wie
  746.       bei einem normalen Programm: In der Hauptquelldatei der DLL (mit der
  747.       Überschrift "library") wird die Unit UseHDeb als erste in die uses-
  748.       Klausel eingefügt.
  749.  
  750.       Der Exit-Code der Unit UseHDeb (mit der Reportausgabe) wird beim Beenden
  751.       der DLL durchgeführt. Wann ist das ? Die DLL wird normalerweise beendet,
  752.       wenn auch das Hauptprogramm, das die DLL geladen hat, beendet wird. Es
  753.       gibt allerdings Ausnahmen. Wenn man das Hauptprogramm mit dem externen
  754.       Debugger ausführt, so wird die DLL nicht bei Programmende abgeschlossen,
  755.       sondern beim Verlassen des Debuggers, was dann aus unerfindlichen Grün-
  756.       den häufig zu einem Absturz des Rechners führt. Es empfiehlt sich daher
  757.       sehr, eine DLL, die den Heap Debugger einbindet, zur Laufzeit des Haupt-
  758.       programms gezielt mit der Anweisung "FreeLibrary" zu beenden, wodurch
  759.       der Exit-Code der Unit UseHDeb für die DLL ausgeführt und somit der Re-
  760.       port ausgegeben wird.
  761.  
  762.       Das bisher Gesagte gilt für DLLs unter DOS und unter Windows gleicher-
  763.       maßen.
  764.  
  765.       Seite 14
  766.  
  767.  
  768.       Unter Windows ergibt sich aber noch ein zusätzliches Problem: Die Re-
  769.       portausgabe, die von der Unit UseHDeb unter Windows ja in ein WinCrt-
  770.       Fenster vorgenommen wird, klappt bei einer DLL nicht: Die Folge des Ver-
  771.       suches, eine Reportausgabe aus einer DLL heraus in ein WinCrt-Fenster
  772.       vorzunehmen, ist in aller Regel entweder ein Laufzeitfehler oder das
  773.       völlige Ausbleiben jeder Ausgabe. Unter DOS gibt es diese Probleme
  774.       nicht.
  775.  
  776.       Es ist unter Windows bei Einsatz des Heap Debuggers in einer DLL also
  777.       unbedingt notwendig, die Ausgaben der Unit UseHDeb in eine Datei umzu-
  778.       leiten. Hierfür wurde der Schalter "REPORT_TO_FILE" vorbereitet (siehe
  779.       hierzu "Compilerschalter in USEHDEB").
  780.  
  781.  
  782.       ___ Programminstanzen (Windows) ________________________________________
  783.  
  784.       Wenn unter Windows ein Programm, das den Heap Debugger einbindet, in
  785.       mehreren Instanzen gestartet wird, so wird nur für die erste Instanz der
  786.       Heap Debugger installiert. Folgende Instanzen nutzen automatisch den
  787.       schon installierten Heap Debugger mit. Die Ausgabe des Reports erfolgt
  788.       erst nach Beenden der letzten aktiven Instanz des Programms, und der Re-
  789.       port beinhaltet alle Heap-Operationen, die in anderen Instanzen des sel-
  790.       ben Programms vorgenommen wurden, ohne das die verursachenden Instanzen
  791.       in dem Report voneinander unterschieden werden können. Um die Übersicht-
  792.       lichkeit zu wahren, sollten also möglichst nicht mehrere Instanzen aus-
  793.       geführt werden.
  794.  
  795.  
  796.       ___ Interrupts ________________________________________________________
  797.  
  798.       Der Heap Debugger benötigt für seine Arbeit drei eigene Softwareinter-
  799.       rupts. Das heißt, daß der Heap Debugger bei der Installation drei freie
  800.       Interruptvektoren belegt und diese bei Programmende wieder restauriert.
  801.       Der Heap Debugger sucht sich die freien Softwareinterrupts selbst aus,
  802.       und zwar im Bereich 78h bis FFh. Aus diesem Bereich können gezielt ein-
  803.       zelne Interrupts vom Programmierer ausgeschlossen werden, indem in der
  804.       Unit UseHDeb.PAS die Anweisung "HeapDebInit([])" verändert wird. In der
  805.       als Parameter angegebenen leeren Menge kann eine Menge von Interruptnum-
  806.       mern definiert werden, die vom Heap Debugger nicht benutzt werden
  807.       sollen. Eine Änderung dieses Aufrufes in "HeapDebInit([$F0..$FF])" würde
  808.       z.B. die Interruptvektoren F0h bis FFh für die Benutzung durch den Heap
  809.       Debugger ausschließen und somit für das Hauptprogramm freihalten.
  810.  
  811.  
  812.       ___ Stabilität und Performance _________________________________________
  813.  
  814.       Wie schon erläutert sollte der Heap Debugger nicht als Bestandteil fer-
  815.       tiger Applikationen eingesetzt werden. Der Heap Debugger sollte aus-
  816.       schließlich als Debuggingwerkzeug in der Entwicklungsphase verwendet
  817.       werden.
  818.  
  819.       Der permanente Einsatz des Heap Debuggers während der Softwareentwick-
  820.       lung kann die Stabilität der entwickelten Software erheblich verbessern
  821.       und die Entwicklungszeit verkürzen.
  822.  
  823.       Es ist jedoch nicht auszuschließen, daß der Heap Debugger in der Ent-
  824.       wicklungsphase eine potentielle Ursache für Programmabstürze sein kann,
  825.       auch wenn dies von uns bisher nicht beobachtet werden konnte. Folgende
  826.       Tatsachen sollten beachtet werden:
  827.  
  828.       Seite 15
  829.  
  830.  
  831.       - Der Heap Debugger überwacht nicht nur die korrekte Verwendung des
  832.         Heapspeichers. Er benötigt auch selbst Heapspeicher für diese Aufgabe.
  833.         Wenn ein Programm zeitweise eine große Anzahl von Heapspeicherblöcken
  834.         allokiert, so kann der zusätzliche Speicherbedarf des Heap Debuggers
  835.         erheblich sein. Mit zusätzlichen 24 Byte je allokiertem (und noch
  836.         nicht wieder deallokiertem) Speicherblock sollte gerechnet werden.
  837.       - Die Ausführung des Heap Debuggers erfordert zusätzlich Platz auf dem
  838.         Stack, und zwar sowohl bei der Ausführung von Speicheroperationen als-
  839.         auch bei der Ausgabe der Reports in der Exitprozedur der Unit UseHDeb.
  840.         Hier ist zu beachten, daß teilweise keine Überprüfung des Stacks mög-
  841.         lich ist, so daß ein zu klein dimensionierter Stack ein Programm zum
  842.         Absturz bringen kann.
  843.       - Bei massiven Fehlern des Applikationsprogrammierers bei dem Umgang mit
  844.         Heapspeicher kann der Einsatz des Heap Debuggers, der wie gesagt auch
  845.         selbst mit Heapspeicher arbeitet, den Absturz eines Programmes sogar
  846.         erst auslösen, was, in einer zufällig anderen Konstellation, ohne den
  847.         Heap Debugger vielleicht nicht passiert wäre. Solche Abstürze können
  848.         zum Beispiel dann passieren, wenn die Applikation versucht, einen vor-
  849.         her gar nicht allokierten Speicherbereich freizugeben. In diesem Fall
  850.         ist ein Programmabsturz als klares Indiz für einen Programmierfehler
  851.         jedenfalls einem trügerischen fehlerfreien Programmablauf vorzuziehen.
  852.       - Der Heap Debugger braucht für seine Arbeit zusätzliche Rechenzeit. Je
  853.         mehr Speicherblöcke allokiert werden, um so mehr steigt der Zeitbedarf
  854.         des Heap Debuggers, insbesondere beim Wiederfreigeben von Speicher.
  855.         Diese Performanceeinbuße wird aber allenfalls bei sehr zeitkritischen
  856.         Anwendungen irgendwie spürbar sein.
  857.       - Der Heap Debugger benötigt, wie schon im vorherigen Abschnitt erwähnt,
  858.         für seine Arbeit drei freie Softwareinterrupts, deren Vektoren er zum
  859.         Anfang des Programms auf eigene Routinen umlenkt und zum Ende des Pro-
  860.         gramms wieder restauriert. Wenn ein Programm durch einen fatalen Feh-
  861.         ler so abrupt beendet wird, daß die Exitprozedur von UseHDeb nicht
  862.         mehr durchlaufen wird, dann werden auch diese Interruptvektoren nicht
  863.         mehr wieder auf ihre alten Werte eingestellt. Wenn anschließend gela-
  864.         dene Programme aber von korrekten Werten in diesen Vektoren abhängig
  865.         sind, so kann dies zu Problemen führen. Wenn sich solche Abstürze sehr
  866.         häufig wiederholen, dann kann der Heap Debugger irgendwann keine
  867.         freien Interrupts mehr finden und kann nicht gestartet werden.
  868.  
  869.  
  870.       ___ Eingriffsmöglichkeiten für den Programmierer _______________________
  871.  
  872.       Es ist für einige Fälle denkbar, daß ein Programmierer Änderungen am
  873.       Heap Debugger vornehmen möchte, um z.B. die Reportausgabe seinen eigenen
  874.       Vorstellungen anzupassen. Aus diesem Grunde wird die Unit UseHDeb im
  875.       Quellcode mitgeliefert. Programmänderungen dürfen nur an dieser Unit und
  876.       nur zu eigenen, nichtkommerziellen Zwecken vorgenommen werden.
  877.  
  878.       Darüberhinaus bietet das Interface der Unit HDeb7?.TP? folgende typi-
  879.       sierte Konstanten an, die zur Laufzeit eines Programms verändert werden
  880.       können:
  881.  
  882.       Seite 16
  883.  
  884.  
  885.       1)   SuspendHeapdeb : Boolean = false;
  886.  
  887.       Wird diese Konstante zur Laufzeit des Hauptprogramms auf TRUE gesetzt,
  888.       so werden anschließend keine Heap Operationen vom Heap Debugger mehr
  889.       aufgezeichnet. Nach Rückänderung des Wertes auf FALSE arbeitet der Heap
  890.       Debugger wieder normal. Dies kann z.B. nützlich sein, um quasi statische
  891.       Allokationen, die sonst bei jeder Reportausgabe des Heap Debuggers auf-
  892.       geführt werden, für den Heap Debugger "unsichtbar" zu machen und dadurch
  893.       einen "sauberen" Report zu ermöglichen.
  894.  
  895.       2)   RecordZeroSize : Boolean = false;
  896.  
  897.       Solange diese Konstante den Wert FALSE hat, werden Allokationen und De-
  898.       allokationen mit der Länge Null vom Heap Debugger ignoriert. Weil solche
  899.       Operationen reine Schönheitsfehler sind und unseres Wissens keinen Scha-
  900.       den anrichten können, ist diese Konstante auf FALSE voreingestellt.
  901.  
  902.       3)   RTEOnWrongSizedFree : Byte = 0;
  903.  
  904.       Wenn in diese Konstante ein anderer Wert als Null geladen wird, dann
  905.       wird bei jeder Deallokation, die nicht die gleiche Länge wie die zuge-
  906.       hörige Allokation aufweist (Flag "S"), sofort ein Run-Time-Error ausge-
  907.       löst. Die Nummer des Run-Time-Errors wird durch diese Konstante
  908.       bestimmt.
  909.  
  910.       4)   RTEOnUnknownFree : Byte = 0;
  911.  
  912.       Wenn in diese Konstante ein anderer Wert als Null geladen wird, dann
  913.       wird bei jeder Deallokation, zu der keine passende Allokation (gleiche
  914.       Anfangsadresse des Heapspeicherblocks) gefunden werden kann (Flag "M"),
  915.       sofort ein Run-Time-Error ausgelöst. Die Nummer des Run-Time-Errors wird
  916.       durch diese Konstante bestimmt.
  917.  
  918.  
  919.       BEKANNTE EINSCHRÄNKUNGEN UND PROBLEME __________________________________
  920.  
  921.       ___ Mark/Release _______________________________________________________
  922.  
  923.       Von der Verwendung der Befehle Mark und Release erhält der Heap Debugger
  924.       keinerlei Kenntnis und kann sie also auch nicht berücksichtigen. Darüber
  925.       hinaus kann die Anweisung Release den Heap Debugger erheblich stören
  926.       (bis hin zum Programmabsturz), weil dadurch eventuell auch Aufzeichnun-
  927.       gen des Heap Debuggers verworfen werden, ohne daß der Heap Debugger die-
  928.       ses erkennen kann.
  929.  
  930.       Allerdings werden die Befehle Mark und Release fast gar nicht mehr ver-
  931.       wendet, denn sie bringen, unabhängig von der Unverträglichkeit mit dem
  932.       Heap Debugger, noch eine Reihe anderer Probleme mit sich. Wahrscheinlich
  933.       sind sie in der aktuellen Version des Compilers nur noch aus Kompatibi-
  934.       litätsgründen implementiert. Von der Verwendung von Mark und Release ist
  935.       also allgemein abzuraten. Mark und Release stehen nur unter DOS zur Ver-
  936.       fügung.
  937.  
  938.       Seite 17
  939.  
  940.  
  941.       ___ MemAllocSeg ________________________________________________________
  942.  
  943.       Die Funktion MemAllocSeg in der Unit Memory (unter Windows: OMemory)
  944.       stellt den Heap Debugger vor ein großes Problem: Die Aufgabe dieser
  945.       Funktion ist es, einen Heapspeicherbereich anzufordern, dessen Anfangs-
  946.       adresse genau auf dem Anfang eines Speichersegmentes liegt, also die
  947.       Offsetadresse 0000 hat. Um dieses zu erreichen, greift die Funktion
  948.       MemAllocSeg tief in die Trickkiste, wobei wir zwischen den verschiedenen
  949.       Zielplattformen unterscheiden müssen:
  950.  
  951.       Real Mode:
  952.  
  953.       Um garantiert einen Heapspeicherbereich mit der Offsetadresse 0000 allo-
  954.       kieren zu können, reserviert die Funktion MemAllocSeg mittels GetMem zu-
  955.       nächst einen etwas größeren Bereich, um anschließend sofort wieder einen
  956.       kleinen Teil davon (nämlich 8 Bytes), die entweder am Anfang oder am
  957.       Ende des gerade allokierten größeren Bereichs liegen, mittels FreeMem
  958.       freizugeben. Hier wird also etwas getan, was zwar in engen Grenzen er-
  959.       laubt, aber verpönt ist: Der Heap Debugger "beobachtet" diese Operatio-
  960.       nen und wird sie später in seinem Report ausgeben. Das kann dann z.B. so
  961.       aussehen:
  962.  
  963.          program TEST;
  964.          uses UseHDeb, Memory;
  965.          var p: pointer;
  966.          begin
  967.            {...}
  968.            p := MemAllocSeg(100);
  969.            FreeMem(p, 100);
  970.          end.
  971.  
  972.       HEAP-DEBUGGER-DIAGNOSE:
  973.       1 Pointer wurden registiert
  974.       3 Debug-Eintraege vorhanden
  975.       auflisten (J/N) ? j
  976.  
  977.       Nr    Pointer   Size  Flags          Aufrufer         Datei  Zeile
  978.        1  1A4D:0000    112    S     020B[1438]:001F    MEMORY.PAS    327
  979.           1A53:0008      8   F M    020B[1438]:00D5    MEMORY.PAS    355
  980.           1A4D:0000    100   FS     0000[122D]:003A      TEST.PAS      7
  981.  
  982.       Oder so:
  983.  
  984.       HEAP-DEBUGGER-DIAGNOSE:
  985.       1 Pointer wurden registiert
  986.       3 Debug-Eintraege vorhanden
  987.       auflisten (J/N) ? j
  988.  
  989.       Nr    Pointer   Size  Flags          Aufrufer         Datei  Zeile
  990.        1  1531:0008    112    S     020C[0F1A]:001F    MEMORY.PAS    327
  991.           1531:0008      8   FS     020C[0F1A]:00D5    MEMORY.PAS    355
  992.           1532:0000    100   F M    0000[0D0E]:004A      TEST.PAS      7
  993.  
  994.       Der Programmierer ist wohl oder übel gezwungen, solche nicht ganz ast-
  995.       reinen Heap-Operationen zu dulden und derartige Diagnosen des Heap
  996.       Debuggers zu ignorieren.
  997.  
  998.       Seite 18
  999.  
  1000.  
  1001.       (Die Referenz auf die Sourcecodestellen in der Unit Memory werden nur
  1002.        dann ausgegeben, wenn diese Unit mit der Option $D+ übersetzt worden
  1003.        ist.)
  1004.  
  1005.       Protected Mode (DOS/DPMI):
  1006.  
  1007.       Hier hat es die Funktion MemAllocSeg etwas einfacher als im Real Mode:
  1008.       Sie ruft einfach die Funktion "MemAllocateBlock" auf, welche von der
  1009.       RTM.EXE zur Verfügung gestellt wird und eine entsprechene DPMI-Funktion
  1010.       darstellt. Dadurch wird ein Heapspeicherblock allokiert, der garantiert
  1011.       bei der Offsetadresse 0000 beginnt. Wie schon im Abschnitt "Globaler und
  1012.       lokaler Heap" beschrieben, erhält der Heap Debugger von diesem Vorgang
  1013.       keine Kenntnis. Die Freigabe des so allokierten Heapspeicherblocks wird
  1014.       jedoch überlicherweise mit der Funktion FreeMem vorgenommen, wovon der
  1015.       Heap Debugger sehr wohl Kenntnis erhält. Das oben gezeigte TestProgramm
  1016.       würde also im Protected Mode folgende Reportausgabe hervorrufen:
  1017.  
  1018.       HEAP-DEBUGGER-DIAGNOSE:
  1019.       0 Pointer wurden registiert
  1020.       1 Debug-Eintraege vorhanden
  1021.       auflisten (J/N) ? j
  1022.  
  1023.         Nr    Pointer   Size  Flags          Aufrufer         Datei  Zeile
  1024.             059F:0000    100   F M    0001[0547]:003D      TEST.PAS      7
  1025.  
  1026.       Windows:
  1027.  
  1028.       Hier gilt das gleiche wie im Protected Mode unter DOS, nur daß sich die
  1029.       Funktion MemAllocSeg der Funktion "GlobalAlloc" bedient, um einen Heap-
  1030.       speicherbereich mit der Offsetadresse 0000 zu allokieren. Da es sich
  1031.       hier um eine Operation mit dem globalen Heap handelt, merkt der Heap
  1032.       Debugger davon nichts. Die Freigabe dieses Heapspeicherbereichs mittels
  1033.       FreeMem wird aber registiert. Die Konsequenz für den Heap Debugger ist
  1034.       die gleiche wie im Protected Mode unter DOS.
  1035.  
  1036.  
  1037.       ___ BGI ________________________________________________________________
  1038.  
  1039.       Bei der Initialisierung von BGI-Treibern tritt mitunter das bei
  1040.       "MemAllocSeg" beschriebene Problem auf. Vermutlich verwenden BGI-Treiber
  1041.       oder die Unit Graph eine eigene Implementation der Funktion
  1042.       "MemAllocSeg".
  1043.  
  1044.  
  1045.       ___ TMemoryStream ______________________________________________________
  1046.  
  1047.       Dieser Stream benutzt in der Methode "ChangeListSize" die Funktion
  1048.       "MemAllocSeg", die weiter oben beschrieben ist.
  1049.  
  1050.  
  1051.       ___ Heapüberlauf _______________________________________________________
  1052.  
  1053.       Der Heap Debugger, der ja die Heap-Operationen eines Programms überwa-
  1054.       chen soll, benötigt für seine Arbeit selbst ebenfalls Heapspeicher.
  1055.       Falls der Heap Debugger selbst keinen Heapspeicher mehr anfordern kann,
  1056.       weil dieser aufgebraucht ist, so wird bei der Reportausgabe ein Interner
  1057.       Fehler Nummer 203 gemeldet. Wenn das Hauptprogramm eine HeapError-Funk-
  1058.       tion definiert hat, dann kommt diese auch beim Scheitern einer Heapallo-
  1059.       kation innerhalb des Heap Debuggers zur Ausführung.
  1060.  
  1061.       Seite 19
  1062.  
  1063.  
  1064.       ___ Programmabbruch ____________________________________________________
  1065.  
  1066.       Wird ein Programm, das den Heap Debugger einbindet, abgebrochen, ohne
  1067.       daß die Exit-Prozedur der Unit UseHDeb (die den Report ausgibt) durch-
  1068.       laufen wird, so werden die von vom Heap Debugger veränderten Software-
  1069.       interrupts nicht restauriert und stehen danach - zumindest für den Heap
  1070.       Debugger - nicht mehr als freie Interruptvektoren zur Verfügung. Nicht
  1071.       restaurierte Interruptvektoren, die sonst nirgens verwendet werden,
  1072.       stellen eigentlich kaum eine Gefahr dar, da diese Interrupts eigentlich
  1073.       von keinem Programm aufgerufen werden. Beim Neuinitialisieren des Heap
  1074.       Debuggers bei einem neuerlichen Programmstart werden aber wieder drei
  1075.       andere Interruptvektoren ausgesucht. Wenn sich die "harten" Abstürze
  1076.       wiederholen (ca. 40 mal), stehen irgendwann keine freien Interruptvekto-
  1077.       ren mehr zur Verfügung und der Heap Debugger kann nicht mehr initiali-
  1078.       siert werden, was sich nur durch einen Neustart des Rechners beheben
  1079.       läßt.
  1080.  
  1081.  
  1082.       ___ WINCRT _____________________________________________________________
  1083.  
  1084.       Wenn das Hauptprogramm schon ein WinCrt-Fenster benutzt und dieses nicht
  1085.       mit DoneWinCrt geschlossen wird, bevor die Exit-Prozedur der Unit
  1086.       UseHDeb durchlaufen wird, dann bleiben typischerwiese 2000 Byte Heap-
  1087.       speicher allokiert, die dann im Heap Debugger Report aufgeführt werden.
  1088.  
  1089.       Man sollte deswegen aber im Hauptprogramm kein DoneWinCrt-Kommando pro-
  1090.       grammieren, denn dies führt oft bei der Reportausgabe des Heap Debuggers
  1091.       zu neuen Problemen.
  1092.  
  1093.       Wie schon im Abschnitt "DLLs" beschrieben, kann der Heap Debugger bei
  1094.       der Einbindung in eine DLL keine Ausgabe in ein WinCrt-Fenster machen.
  1095.  
  1096.       In allen Zweifelsfällen sollte man versuchen, auf die Möglichkeit der
  1097.       Reportausgabe in eine Datei auszuweichen.
  1098.  
  1099.